package com.swak.hazelcast;

import java.util.concurrent.TimeUnit;

import com.hazelcast.map.IMap;
import com.swak.App;
import com.swak.cache.Cache;
import com.swak.cache.Entity;
import com.swak.codec.SafeEncoder;
import com.swak.exception.SerializeException;
import com.swak.redis.NameableCache;

public class HazelcastCache<T> extends NameableCache implements Cache<T> {

	private HazelcastCacheManager cacheManager;
	private final IMap<String, byte[]> map;

	/**
	 * 默认不过期
	 * 
	 * @param name
	 */
	public HazelcastCache(String name) {
		super(name);
		this.map = cacheManager.getHazelcast().getMap(name);
	}

	/**
	 * 指定过期时间
	 * 
	 * @param name
	 * @param timeToIdle
	 */
	public HazelcastCache(String name, int timeToIdle) {
		super(name, timeToIdle);
		this.map = cacheManager.getHazelcast().getMap(name);
	}

	/**
	 * 指定过期时间, 过期方式
	 * 
	 * @param name
	 * @param timeToIdle
	 */
	public HazelcastCache(String name, int timeToIdle, boolean idleAble) {
		super(name, timeToIdle, idleAble);
		this.map = cacheManager.getHazelcast().getMap(name);
	}

	/**
	 * 设置缓存管理器
	 * 
	 * @param cacheManager
	 * @return
	 */
	public HazelcastCache<T> setCacheManager(HazelcastCacheManager cacheManager) {
		this.cacheManager = cacheManager;
		return this;
	}

	@Override
	@SuppressWarnings("unchecked")
	public T getObject(String key) {
		try {
			if (!idleAble()) {
				return (T) App.deserialize(this._get(key));
			}
			return (T) App.deserialize(this._hget(key));
		} catch (SerializeException e) {
			this._del(key);
			return null;
		}
	}

	private byte[] _get(String key) {
		String keyName = this.getKeyName(key);
		return this.map.get(keyName);
	}

	private byte[] _hget(String key) {
		String keyName = this.getKeyName(key);
		this.map.setTtl(keyName, this.getLifeTime(), TimeUnit.MICROSECONDS);
		return this.map.get(keyName);
	}

	@Override
	public String getString(String key) {
		if (!idleAble()) {
			return SafeEncoder.encode(this._get(key));
		}
		return SafeEncoder.encode(this._hget(key));
	}

	@Override
	public Long delete(String key) {
		return this._del(key);
	}

	@Override
	public Long delete(String... keys) {
		return this._del(keys);
	}

	private long _del(String... keys) {
		long count = 0;
		for (String key : keys) {
			String keyName = this.getKeyName(key);
			this.map.delete(keyName);
			count++;
		}
		return count;
	}

	@Override
	public Boolean exists(String key) {
		if (!idleAble()) {
			return _exists(key);
		}
		return _hexists(key);
	}

	private boolean _exists(String key) {
		return this.map.containsKey(this.getKeyName(key));
	}

	private boolean _hexists(String key) {
		String keyName = this.getKeyName(key);
		this.map.setTtl(keyName, this.getLifeTime(), TimeUnit.MICROSECONDS);
		return this.map.containsKey(keyName);
	}

	@Override
	public Entity<T> putObject(String key, T value) {
		this._set(key, App.serialize(value));
		return new Entity<T>(key, value);
	}

	@Override
	public Entity<String> putString(String key, String value) {
		this._set(key, SafeEncoder.encode(value));
		return new Entity<String>(key, value);
	}

	/**
	 * 原生的设置
	 * 
	 * @param key
	 * @param value
	 * @param expiration
	 */
	protected void _set(String key, byte[] value) {
		String keyName = this.getKeyName(key);
		if (isValid()) {
			this.map.set(keyName, value, this.getLifeTime(), TimeUnit.MICROSECONDS);
		} else {
			this.map.set(keyName, value);
		}
	}

	@Override
	public Long ttl(String key) {
		this.map.setTtl(getKeyName(key), this.getLifeTime(), TimeUnit.MICROSECONDS);
		return Long.valueOf(this.getLifeTime());
	}
}
